﻿Public Class FrmClient
    Private th As System.Threading.Thread
    Private ReadOnly MQ As New Queue(Of String)()
    Private Sub FrmClient_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Icon = My.Resources.update
        NotifyIcon1.Icon = My.Resources.update
        NotifyIcon1.Text = "文件同步客户端"
        NotifyIcon1.Visible = True
        TextBox1.Text = My.Settings.BackPath
        TextBox2.Text = My.Settings.ServerIP
        TextBox3.Text = My.Settings.MyName
        CheckBox1.Checked = My.Settings.IsDel
        NumericUpDown1.Value = My.Settings.FDelay
        CheckBox2.Checked = My.Settings.StartonWindow
        CheckBox3.Checked = My.Settings.IsAutoStart
        CheckBox4.Checked = My.Settings.IsSubDIR
        If CheckBox3.Checked Then
            '--隐藏窗口
            Visible = False
            '--变量赋值
            th = New System.Threading.Thread(AddressOf Start)
            th.Start()
            '---线程启动循环
            Timer1.Interval = My.Settings.FDelay * 1000
            Timer1.Enabled = True
            Timer1.Start()
            '---消息循环
            Timer2.Interval = 1000
            Timer2.Enabled = True
            Timer2.Start()
        End If
    End Sub
    '--检查文件是否可用
    Private Sub CheckFile()

    End Sub
    '--对比文件
    Private Sub CPFile()

    End Sub
    '--传送文件
    Private Sub SendFile()

    End Sub
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        FolderBrowserDialog1.SelectedPath = ""
        If FolderBrowserDialog1.ShowDialog() = DialogResult.OK Then
            TextBox1.Text = FolderBrowserDialog1.SelectedPath
        End If
    End Sub
    Private Sub SaveCFG()

        '--保存配置 
        My.Settings.ServerIP = TextBox2.Text
        My.Settings.BackPath = TextBox1.Text
        My.Settings.MyName = TextBox3.Text
        My.Settings.IsDel = CheckBox1.Checked
        My.Settings.FDelay = NumericUpDown1.Value
        My.Settings.StartonWindow = CheckBox2.Checked
        My.Settings.IsAutoStart = CheckBox3.Checked
        My.Settings.IsSubDIR = CheckBox4.Checked
        My.Settings.Save()
        '--开机启动处理,直接添加注册表,我比较懒直接用my来改,问题是不能删除
        If My.Settings.StartonWindow Then
            '---开机启动
            My.Computer.Registry.SetValue("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run", "FSClient", Application.ExecutablePath)
        Else
            '---删除开机启动
            My.Computer.Registry.SetValue("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run", "FSClient", "")
        End If

    End Sub
    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click

        '--变量赋值
        th = New System.Threading.Thread(AddressOf Start)
        th.Start()
        '---线程启动循环
        Timer1.Interval = My.Settings.FDelay * 1000
        Timer1.Enabled = True
        Timer1.Start()
        '---消息循环
        Timer2.Interval = 1000
        Timer2.Enabled = True
        Timer2.Start()
    End Sub
    Private Sub Start()
        MQ.Enqueue("开始执行")
        '--获取文件名
        Dim Files As String() = System.IO.Directory.GetFiles(My.Settings.BackPath)
        MQ.Enqueue("获取文件名...")
        
        
        '--定义变量
        Dim FileName As String = String.Empty
        Dim FileSize As Integer = 0
        Dim FileDate As String = String.Empty
        Dim FInfo As IO.FileInfo
        Dim EP As New System.Net.IPEndPoint(System.Net.IPAddress.Parse(My.Settings.ServerIP), 8800)
        Dim FSender As New System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, Net.Sockets.SocketType.Stream, Net.Sockets.ProtocolType.Tcp)
        Dim CVT As New System.Text.UTF8Encoding
        Dim FContent As Byte() = Nothing
        Dim FRecv As Integer = 0
        '--连接服务器
        Try
            MQ.Enqueue("连接服务器...")
            FSender.Connect(EP)
            FSender.ReceiveTimeout = 60000
            MQ.Enqueue("连接成功,发送客户端名...")
            FContent = New Byte(3) {}
            FContent = BitConverter.GetBytes(CVT.GetBytes(My.Settings.MyName).Length)
            '--设置发送缓冲区200MB
            FSender.SendBufferSize = 209715200

            '----连接成功,发送本机客户端名
            '-发送主机名标志
            FSender.Send(CVT.GetBytes("CLNME"))
            '-通知长度
            FSender.Send(BitConverter.GetBytes(CVT.GetBytes(My.Settings.MyName).Length))
            '-发送名称
            FSender.Send(CVT.GetBytes(My.Settings.MyName))
            '--以上不考虑服务器是否正确收到问题,只管发就行
            '--循环比较文件,文件大小用了integer所以不能超过2G.懒人没办法,前面写错了后面就继续错下去吧
            MQ.Enqueue("开始同步进程")

            If CheckBox4.Checked Then
                '---包括子目录
                MQ.Enqueue("选择了包括子目录,开始循环获取文件...")
                Files = New String() {}
                Dim TmpDIR As String() = New String() {My.Settings.BackPath}
                Dim i1 As Integer = 0
                While i1 < TmpDIR.Length
                    '--检查是否为系统文件夹
                    Dim FTMpINF As New IO.DirectoryInfo(TmpDIR(i1))
                    If Trim(FTMpINF.FullName.Substring(FTMpINF.FullName.IndexOf(":\") + 2)) = String.Empty Then
                        '--根目录
                    Else
                        '--非根目录,判断属性
                        If (FTMpINF.Attributes And IO.FileAttributes.Hidden) = IO.FileAttributes.Hidden Or (FTMpINF.Attributes And IO.FileAttributes.Offline) = IO.FileAttributes.Offline Or (FTMpINF.Attributes And IO.FileAttributes.System) = IO.FileAttributes.System Or (FTMpINF.Attributes And IO.FileAttributes.Temporary) = IO.FileAttributes.Temporary Then
                            MQ.Enqueue("跳过:" & TmpDIR(i1))
                            i1 += 1
                            Continue While
                        End If
                    End If
                    

                    '--获取目录下的所有文件和文件夹
                    Files = System.IO.Directory.GetFiles(TmpDIR(i1))
                    Dim TpDir As String() = System.IO.Directory.GetDirectories(TmpDIR(i1))

                    '--将文件夹写入tmpdir数组
                    If TpDir.Length > 0 Then
                        Array.Resize(TmpDIR, TmpDIR.Length + TpDir.Length)
                        TpDir.CopyTo(TmpDIR, TmpDIR.Length - TpDir.Length)
                    End If
                    For i As Integer = 0 To Files.Length - 1
                        'FInfo = My.Computer.FileSystem.GetFileInfo(Files(i))
                        FInfo = New IO.FileInfo(Files(i))
                        If (FInfo.Attributes And IO.FileAttributes.Hidden) = IO.FileAttributes.Hidden Or (FInfo.Attributes And IO.FileAttributes.Offline) = IO.FileAttributes.Offline Or (FInfo.Attributes And IO.FileAttributes.System) = IO.FileAttributes.System Or (FInfo.Attributes And IO.FileAttributes.Temporary) = IO.FileAttributes.Temporary Or FInfo.Length < 1 Then
                            MQ.Enqueue("跳过:" & FInfo.Name)
                            Continue For
                        End If
                        FileName = FInfo.FullName
                        FileName = FileName.Substring(FileName.IndexOf(":\") + 2)
                        FileSize = FInfo.Length
                        FileDate = FInfo.LastWriteTime
                        MQ.Enqueue("同步:" & FInfo.Name)
                        '--比较文件,从这里开始一但有一个文件出错,后面的都会被影响
                        '--发送文件名
                        FSender.Send(CVT.GetBytes("CFILE"))
                        FSender.Send(BitConverter.GetBytes(CVT.GetBytes(FileName).Length))
                        FSender.Send(CVT.GetBytes(FileName))
                        '--发送文件日期
                        FSender.Send(BitConverter.GetBytes(CVT.GetBytes(FileDate).Length))
                        FSender.Send(CVT.GetBytes(FileDate))
                        '--接收结果
                        FRecv = 0
                        FContent = New Byte(4) {}
                        FRecv = FSender.Receive(FContent, 5, Net.Sockets.SocketFlags.None)
                        If FRecv < 1 Then
                            '--出错,处理下一个
                            MQ.Enqueue("比对出错,同步下一个")
                            Continue For
                        End If
                        '--转换为字符串
                        '--判断下一步操作
                        Select Case CVT.GetString(FContent)
                            Case "CFIOK"
                                '--啥也不做,直接下一个
                                MQ.Enqueue("比对完成,直接同步下一个")
                                Continue For
                            Case "CFUPD"
                                MQ.Enqueue("需要更新,开始传送过程")
                                '--发送文件
                                FSender.Send(CVT.GetBytes("SFILE"))
                                '--文件长度
                                FSender.Send(BitConverter.GetBytes(FileSize))
                                '--文件名
                                FSender.Send(BitConverter.GetBytes(CVT.GetBytes(FileName).Length))
                                FSender.Send(CVT.GetBytes(FileName))
                                '--发送文件
                                FSender.SendFile(Files(i))
                                '--等待主机返回成功命令,防止速度过快导致的线程崩溃
                                FContent = New Byte(4) {}
                                FSender.Receive(FContent, 5, Net.Sockets.SocketFlags.None)
                                '----不管收到的是啥都继续
                                MQ.Enqueue("发送成功,继续")
                                FContent = Nothing
                                Continue For
                            Case "CFDEL"
                                '--删除文件
                                MQ.Enqueue("服务器已有此文件")
                                If CheckBox1.Checked Then
                                    MQ.Enqueue("删除文件")
                                    My.Computer.FileSystem.DeleteFile(Files(i))
                                End If
                        End Select
                    Next
                    '--循环变量加1,继续
                    i1 += 1
                End While
            Else
                For i As Integer = 0 To Files.Length - 1
                    'FInfo = My.Computer.FileSystem.GetFileInfo(Files(i))
                    FInfo = New IO.FileInfo(Files(i))
                    FileName = FInfo.FullName
                    FileName = FileName.Substring(FileName.IndexOf(":\") + 2)
                    FileSize = FInfo.Length
                    FileDate = FInfo.LastWriteTime
                    MQ.Enqueue("同步:" & FInfo.Name)
                    '--比较文件,从这里开始一但有一个文件出错,后面的都会被影响
                    '--发送文件名
                    FSender.Send(CVT.GetBytes("CFILE"))
                    FSender.Send(BitConverter.GetBytes(CVT.GetBytes(FileName).Length))
                    FSender.Send(CVT.GetBytes(FileName))
                    '--发送文件日期
                    FSender.Send(BitConverter.GetBytes(CVT.GetBytes(FileDate).Length))
                    FSender.Send(CVT.GetBytes(FileDate))
                    '--接收结果
                    FRecv = 0
                    FContent = New Byte(4) {}
                    FRecv = FSender.Receive(FContent, 5, Net.Sockets.SocketFlags.None)
                    If FRecv < 1 Then
                        '--出错,处理下一个
                        MQ.Enqueue("比对出错,同步下一个")
                        Continue For
                    End If
                    '--转换为字符串
                    '--判断下一步操作
                    Select Case CVT.GetString(FContent)
                        Case "CFIOK"
                            '--啥也不做,直接下一个
                            MQ.Enqueue("比对完成,直接同步下一个")
                            Continue For
                        Case "CFUPD"
                            MQ.Enqueue("需要更新,开始传送过程")
                            '--发送文件
                            FSender.Send(CVT.GetBytes("SFILE"))
                            '--文件长度
                            FSender.Send(BitConverter.GetBytes(FileSize))
                            '--文件名
                            FSender.Send(BitConverter.GetBytes(CVT.GetBytes(FileName).Length))
                            FSender.Send(CVT.GetBytes(FileName))
                            '--发送文件
                            FSender.SendFile(Files(i))
                            '--等待主机返回成功命令,防止速度过快导致的线程崩溃
                            FContent = New Byte(4) {}
                            FSender.Receive(FContent, 5, Net.Sockets.SocketFlags.None)
                            '----不管收到的是啥都继续
                            MQ.Enqueue("发送成功,继续")
                            FContent = Nothing
                            Continue For
                        Case "CFDEL"
                            '--删除文件
                            MQ.Enqueue("服务器已有此文件")
                            If CheckBox1.Checked Then
                                MQ.Enqueue("删除文件")
                                My.Computer.FileSystem.DeleteFile(Files(i))
                            End If
                    End Select
                Next
            End If
            
            MQ.Enqueue("同步结束,退出线程")
            '--发送断开连接标志
            FSender.Send(CVT.GetBytes("LGOUT"))
            FSender.Disconnect(False)
            FSender.Close()
            FSender.Dispose()
            FSender = Nothing
        Catch ex As Exception
            '--连接失败,退出
            MQ.Enqueue("同步过程中出现问题,线程退出.信息:" & ex.Message)
            Exit Sub
        End Try

    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        If th.ThreadState <> Threading.ThreadState.Running Then
            '--清空记录框
            TextBox4.Text = String.Empty
            th = New System.Threading.Thread(AddressOf Start)
            th.Start()
        End If
    End Sub

    Private Sub Timer2_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer2.Tick
        If MQ.Count > 0 Then
            For i As Integer = 0 To MQ.Count - 1
                If TextBox4.Text.Length > 5000 Then
                    TextBox4.Text = String.Empty
                End If
                TextBox4.AppendText(MQ.Dequeue & vbCrLf)
            Next
        End If
    End Sub

    Private Sub FrmClient_LocationChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.LocationChanged
        If WindowState = FormWindowState.Minimized Then
            Visible = False
        End If
    End Sub

    Private Sub NotifyIcon1_MouseClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles NotifyIcon1.MouseClick
        If Visible = False Then
            Visible = True
        Else
            Visible = False
        End If
    End Sub

    Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        SaveCFG()
    End Sub
End Class
